use crate::controller::error::Error;
use crate::service::ServiceSet;
use crate::{dto, mq};
use std::sync::Arc;

pub struct EndpointWireguardConfigController {
    service_set: Arc<ServiceSet>,
    event_handler: EventHandler,
}

impl EndpointWireguardConfigController {
    pub fn new(service_set: Arc<ServiceSet>, mq_client_set: Arc<mq::client::ClientSet>) -> Self {
        Self {
            service_set,
            event_handler: EventHandler::new(mq_client_set),
        }
    }

    pub async fn get(
        &self,
        request: &dto::endpoint_wireguard_config::GetRequest,
    ) -> Result<dto::core::endpoint_wireguard_config::EndpointWireguardConfig, Error> {
        let data = self.service_set
            .endpoint_wireguard_config
            .get(request.endpoint_id.as_str())
            .await?;
        
        Ok(data)
    }

    pub async fn try_get(
        &self,
        request: &dto::endpoint_wireguard_config::GetRequest,
    ) -> Result<Option<dto::core::endpoint_wireguard_config::EndpointWireguardConfig>, Error> {
        let data = self.service_set
            .endpoint_wireguard_config
            .try_get(request.endpoint_id.as_str())
            .await?;

        Ok(data)
    }

    pub async fn update(
        &self,
        request: &dto::endpoint_wireguard_config::UpdateRequest,
    ) -> Result<(), Error> {
        if request.params == Default::default() {
            return Ok(());
        }

        let endpoint = self
            .service_set
            .endpoint_manager
            .get(request.endpoint_id.as_str())
            .await?;

        self.service_set
            .endpoint_wireguard_config
            .update(request.endpoint_id.as_str(), &request.params)
            .await?;

        self.event_handler
            .spawn_handle_setup_event(
                endpoint.inner.node_id.as_str(),
                request.endpoint_id.as_str(),
            );

        Ok(())
    }
}

struct EventHandler {
    mq_client_set: Arc<mq::client::ClientSet>,
}

impl EventHandler {
    fn new(mq_client_set: Arc<mq::client::ClientSet>) -> Self {
        Self { mq_client_set }
    }

     fn spawn_handle_setup_event(&self, node_id: &str, endpoint_id: &str) {
        let mq_client_set = self.mq_client_set.clone();
        let node_id = node_id.to_string();
        let endpoint_id = endpoint_id.to_string();

        tokio::spawn(async move {
            if let Err(err) = mq_client_set
                .node
                .endpoint
                .wireguard_config
                .publish_setup_event(node_id.as_str(), endpoint_id.as_str())
                .await
            {
                log::error!("{:?}", err);
            }
        });
    }
}